#ifndef ENCODER_H
#define ENCODER_H

#include "EncoderSettings.h"
#include "Matrix.h"
#include "QuantizationMatrix.h"
#include "BitStream.h"
#include "BlockList.h"
#include "parallelSettings.h"

class Encoder
{
public:
    Encoder() {}
    Encoder(QuantizationMatrix* qm, bool rle, int width, int height,  int matrixColumnSize);
    Encoder (EncoderSettings &config, QuantizationMatrix* qm, int matrixColumnSize);
    ~Encoder() { }

    util::BitStreamWriter *encodePFrame(uint8_t* buff, uint8_t* previousFrame);
    util::BitStreamWriter *encode(uint8_t* buff);

private:
    Matrix *_DCTMatrix;
    Matrix *_tDCTMatrix;
    QuantizationMatrix *_quantizationMatrix;
    uint8_t* _previousFrame;
    bool _RLE;
    int _totalBlocks;
    int _width;
    int _height;
    BlockList _blockList;
    string _logFile;
    int _matrixColumnLength;
    int _matrixSize;
    int _columnSize;
    int _meRange;

    void initDCTMatrices();

    void performNormalization(Matrix& m);
    void performFDCT(Matrix& m);
    void performQuantization(Matrix& m);
    uint32_t calculateMotionVector(int8_t* x, int8_t* y, Matrix** bestComparingBlock, Matrix** diff, Matrix* targetBlock, int tbX, int tbY, uint8_t* _previousFrame);
    Matrix* calculateDifference(Matrix* target, Matrix* reference);
    double calculateMAD(Matrix& matrix);
    int8_t *performZigZag();
    unsigned long performRLEncoding(int8_t *imageList, util::BitStreamWriter *bsw);
    unsigned long performRawEncoding(int8_t *imageList, util::BitStreamWriter *bsw);

    unsigned long fillLast0Series(util::BitStreamWriter *bsw, int &seriesOf0);
    unsigned long fillNumber(util::BitStreamWriter *bsw, int8_t &currentNumber);
};

#endif // ENCODER_H
